#pragma once

#include <type_traits>

// has_operator_minus_impl
template <typename _Ty, typename _Uty>
struct has_operator_minus_impl {
  template <typename __Ty = _Ty, typename __Uty = _Uty>
  static auto func(__Ty &&t, __Uty &&u)
      -> decltype(t - u, void(), std::true_type{});

  static auto func(...) -> std::false_type;

  using type = decltype(func(std::declval<_Ty>(), std::declval<_Uty>()));
};

// has_operator_minus
template <typename _Ty, typename _Uty = _Ty>
struct has_operator_minus : has_operator_minus_impl<_Ty, _Uty>::type {};

// has_operator_minus
template <typename _Ty, typename _Uty = _Ty>
inline constexpr bool has_operator_minus_v =
    has_operator_minus<_Ty, _Uty>::type::value;

// has_operator_plus_prefix_impl
template <typename _Ty>
struct has_operator_plus_prefix_impl {
  template <typename __Ty = _Ty>
  static auto func(__Ty &&t) -> decltype(++t, void(), std::true_type{});

  static auto func(...) -> std::false_type;

  using type = decltype(func(std::declval<_Ty>()));
};

// has_operator_plus_prefix
template <typename _Ty>
struct has_operator_plus_prefix : has_operator_plus_prefix_impl<_Ty>::type {};

// has_operator_plus_prefix_v
template <typename _Ty>
inline constexpr bool has_operator_plus_prefix_v =
    has_operator_plus_prefix<_Ty>::type::value;